/*
 * SipServer.cpp
 *
 *  Created on: 2016年9月20日
 *      Author: zhengboyuan
 */

#include "SipServer.h"

#include <resip/stack/ShutdownMessage.hxx>
#include <resip/stack/ExtensionHeader.hxx>
#include <resip/stack/Helper.hxx>
#include <resip/stack/PlainContents.hxx>

#include <resip/dum/MasterProfile.hxx>
#include <resip/dum/InMemorySyncRegDb.hxx>
#include <resip/dum/ClientAuthManager.hxx>
#include <resip/dum/ServerRegistration.hxx>
#include <resip/dum/ClientRegistration.hxx>
#include <resip/dum/ServerAuthManager.hxx>
#include <resip/dum/UserAuthInfo.hxx>
#include <resip/dum/KeepAliveManager.hxx>
#include <resip/dum/ServerInviteSession.hxx>
#include <resip/dum/ClientInviteSession.hxx>
#include <resip/dum/ServerOutOfDialogReq.hxx>

#include "RegUserAuthManager.h"
#include "ResipUtil.h"
#include "ResipSdp.h"
#include "SdpHelper.h"

#include "CRtpMediaChannel.h"
#include "UserAgentTimeout.h"
#include "MediaFormatReadyMessage.h"
#include "MediaFormatReadySink.h"

#include "CLog.h"
#include "TStringUtil.h"
#include "HostAddr.h"
#include "Path.h"
#include "BasicMacro.h"

#include "AppConst.h"
#include "RtpPort.h"

#include "XmlBuilder.h"

#include "DemoMediaSystem.h"
#include "HkMediaSystem.h"

#include "TestG722.h"

static unsigned int MaxRegistrationRetryTime = 60;              // RFC5626 section 4.5 default
static unsigned int BaseRegistrationRetryTimeAllFlowsFailed = 30; // RFC5626 section 4.5 default
#define RESIPROCATE_SUBSYSTEM Subsystem::APP

static const unsigned int TIMER_SERVER_REGISTRATION = 1;
static const unsigned int DURATION_SERVER_REGISTRATION = 2000;

static const unsigned int TIMER_DEVICE_SESSION = 2;
static const unsigned int DURATION_DEVICE_SESSION = 1000 * 30;	/// 设备会话超时, 单位为毫秒




SipServer::SipServer():
	m_profile(new MasterProfile()),
	m_shuttingDown(),
	m_regRetryDelayTime(),
	m_httpServer()
{
	m_pollGroup.reset(FdPollGrp::create());
	m_interruptor.reset(new EventThreadInterruptor(*m_pollGroup));
	m_stackThread.reset(new EventStackThread(m_stack, *m_interruptor, *m_pollGroup));
	m_dum.reset(new DialogUsageManager(m_stack));

	HKG722Decoder::init();
}

SipServer::~SipServer()
{
	m_stack.shutdownAndJoinThreads();
	m_stackThread->shutdown();
	m_stackThread->join();

	m_dum.reset();
	m_profile.reset();

	m_stackThread.reset();

	HKG722Decoder::quit();
}

bool SipServer::start()
{
	std::string ip = config().getString("HK.IP");
	int port = config().getInt("HK.Port");
	std::string user = config().getString("HK.User");
	std::string password = config().getString("HK.Password");
	av::HkMediaSystem* hkSystem = new av::HkMediaSystem();
	hkSystem->setAddress(ip, port);
	hkSystem->setAccount(user, password);

	m_mediaSystem.reset(hkSystem);

#ifdef _DEBUG
	m_mediaSystem.reset(new av::DemoMediaSystem());
#endif //

	m_mediaSystem->setSink(this);

	if (m_mediaSystem)
	{
		
		m_mediaSystem->open();
	}

	setupData();

	setupMasterProfile();
	setupDum();

	try
	{
		m_stack.addTransport(UDP, getLocalPort());
	}
	catch (std::exception& ex)
	{
		CLog::fatal("%s\n", ex.what());
		return false;
	}

	m_stack.run();

	m_stackThread->run();

	ThreadIf::run();

	//startApplicationTimer(TIMER_SERVER_REGISTRATION, DURATION_SERVER_REGISTRATION, 0, Data::Empty);

	registerProxy();

	return true;
}

void SipServer::stop()
{
	if (m_mediaSystem)
	{
		m_mediaSystem->close();
	}

	unregisterProxy();

	ThreadIf::shutdown();

	m_dum->post(new ShutdownMessage());

	join();

}

void SipServer::test()
{
	

	TestG722 test;
	test.test();
}

AppConfig& SipServer::config()
{
	return AppConfig::instance();
}

int SipServer::getLocalPort()
{
	return config().getInt("Sip.Port", 5000);
}

void SipServer::setHttpServer(HttpServer* server)
{
	m_httpServer = server;
}

void SipServer::setupData()
{
	std::string devFile = getDeviceConfigPath();

	AppConst::TALK_RECV_ENABLED = config().getBool("Talk.EnableRecv", false);
}

std::string SipServer::getDeviceConfigPath()
{
#ifdef WIN32
	std::string workDir = comn::Path::getWorkDir();
	std::string pathList[] =
	{
		".",
		"../bin",
		"../../bin",
		"../hkgate",
		workDir
	};

#else
	std::string pathList[] =
	{
		".",
		"/usr/etc/hkgate",
		"/usr/etc",
		"/etc"
	};
#endif //

	return comn::Path::findFile(pathList, ARRAY_SIZE(pathList), "device.ini");
}


std::string SipServer::getMediaAddr()
{
	std::string ip = m_config.get("Sip.IP");
	if (ip.empty())
	{
		ip = getHostAddr();
	}
	return ip;
}

std::string SipServer::getHostAddr()
{
	return util::HostAddr::getHostAddr();
}

void SipServer::registerProxy()
{
	NameAddr userAor;
	userAor.uri().host() = config().getString("Proxy.IP", getHostAddr()).c_str();
	userAor.uri().port() = config().getInt("Proxy.Port", 5060);
	userAor.uri().user() = config().getString("Sip.User", "hkgate").c_str();

	UserProfilePtr userProfile = m_profile;

    SharedPtr<SipMessage> regMessage = m_dum->makeRegistration(userAor, userProfile);
    m_dum->send(regMessage);
}

void SipServer::unregisterProxy()
{
	if (m_regHandle.isValid())
	{
		m_regHandle->end();
	}
}


NameAddr SipServer::makeAddrFromAudioUri(const std::string& audio)
{
	NameAddr addr;
	addr.uri().user() = audio.c_str();
	addr.uri().host() = config().getString("Proxy.IP").c_str();
	addr.uri().port() = config().getInt("Proxy.Port", 5060);
	return addr;
}

std::string SipServer::makeUserAnswer(UserAppDialog* userDialog)
{
	std::string str;

	av::NetAddress audioAddr = userDialog->m_audioChannel->getLocalAddr();

	str += "v=0\r\n";
	str += comn::StringUtil::format("o=%s 0 0 IN IP4 %s\r\n", userDialog->m_device.id.c_str(), audioAddr.m_ip.c_str());
	str += "s=linker\r\n";
	str += comn::StringUtil::format("c=IN IP4 %s\r\n", audioAddr.m_ip.c_str());
	str += "t=0 0\r\n";
	str += comn::StringUtil::format("m=audio %d RTP/AVP %d\r\n", audioAddr.m_port, userDialog->m_audioMedium.payload);

	if (userDialog->canTalk() || AppConst::TALK_RECV_ENABLED)
	{
		str += comn::StringUtil::format("a=sendrecv\r\n");
	}
	else
	{
		str += comn::StringUtil::format("a=sendonly\r\n");
	}

	str += comn::StringUtil::format("a=rtpmap:%d %s/8000\r\n", 
		userDialog->m_audioMedium.payload, userDialog->m_audioMedium.codec.c_str());
	//str += comn::StringUtil::format("a=rtpmap:110 telephone-event/8000\r\n");

	return str;
}

std::string SipServer::makeAudioDevOffer(const NameAddr& addr, const std::string& ip, uint16_t port)
{
	return comn::StringUtil::format(
				"v=0\r\n"
				"o=%s 0 0 IN IP4 %s\r\n"
				"s=linker\r\n"
				"c=IN IP4 %s\r\n"
				"t=0 0\r\n"
				"m=audio %d RTP/AVP 0 8\r\n"
				"a=sendrecv\r\n"
				"a=rtpmap:0 PCMU/8000\r\n"
				"a=rtpmap:8 PCMA/8000\r\n"
				,
				addr.uri().user().c_str(), ip.c_str(),
				ip.c_str(),
				port
				);
}



void SipServer::tryCloseSession(MediaSessionPtr& mediaSession)
{
	if (mediaSession->getUserCount() == 0)
	{
		closeSession(mediaSession);
	}
}

void SipServer::closeSession(MediaSessionPtr& mediaSession)
{
	m_mediaSessionMap.removeSession(mediaSession);

	ServerInviteSessionHandle userInvite = mediaSession->removeUser();
	while (userInvite.isValid())
	{
		userInvite->end();

		userInvite = mediaSession->removeUser();
	}

	ClientInviteSessionHandle clientHandle = mediaSession->getInviteSession();
	if (clientHandle.isValid())
	{
		clientHandle->end();
	}

	av::MediaChannelPtr channel = mediaSession->getMediaChannel();
	if (channel)
	{
		channel->close();
	}
}

bool SipServer::handleUserSdp(UserAppDialog* userDialog, InviteSessionHandle handle, const SdpContents& contents)
{
    RtpMedium audioMedium;
    SdpHelper::findPcm(contents, audioMedium);
    audioMedium.empty();

    userDialog->m_audioMedium = audioMedium;

    return true;
}

bool SipServer::handleUserOffer(UserAppDialog* userDialog, InviteSessionHandle handle, const SdpContents& contents)
{
	MediaSessionPtr mediaSession = m_mediaSessionMap.findSession(userDialog->m_device.id);
	if (!mediaSession)
	{
		rejectInvite(handle, 500, "no such audio session");
		return false;
	}

	MediaSession::State state = mediaSession->getState();
	if (state == MediaSession::kInit)
	{
		av::MediaSystem::Device device = userDialog->m_device;
		av::MediaChannelPtr channel = mediaSession->getMediaChannel();
		int ret = channel->open(device.url, device.id);
		if (ret == 0)
		{
			mediaSession->setState(MediaSession::kPending);

			av::MediaSinkPtr sink(new MediaFormatReadySink(*m_dum, device.id.c_str()));
			channel->addSink(sink);
		}
		else
		{
			CLog::warning("failed to open device(%s).\n", device.id.c_str());
			rejectInvite(handle, 500, "failed to open device");
			return false;
		}
	}
	else if (state == MediaSession::kReady)
	{
		av::MediaChannelPtr mediaChannel = mediaSession->getMediaChannel();
		userDialog->setupAudio(mediaChannel, getMediaAddr(), 0);
	}

	if (userDialog->isMediaReady())
	{
		std::string userAnswer = makeUserAnswer(userDialog);

		HeaderFieldValue hfv(userAnswer.c_str(), userAnswer.size());
		Mime type("application", "sdp");
		SdpContents sdpAnswer(hfv, type);

		handle->provideAnswer(sdpAnswer);

		if (!handle->isAccepted())
		{
			ServerInviteSession* inviteSession = (ServerInviteSession*)handle.get();
			inviteSession->accept();
		}
	}

	return true;
}


bool SipServer::handleUserAnswer(UserAppDialog* userDialog, InviteSessionHandle handle, const SdpContents& contents)
{
	MediaSessionPtr mediaSession = m_mediaSessionMap.findSession(userDialog->m_device.id);
	if (!mediaSession)
	{
		rejectInvite(handle, 500, "no such audio session");
		return false;
	}

	MediaSession::State state = mediaSession->getState();
	if (state == MediaSession::kInit)
	{
		av::MediaSystem::Device device = userDialog->m_device;
		av::MediaChannelPtr channel = mediaSession->getMediaChannel();
		int ret = channel->open(device.url, device.id);
		if (ret == 0)
		{
			mediaSession->setState(MediaSession::kPending);
		}
		else
		{
			CLog::warning("failed to open device(%s).\n", device.id.c_str());
			rejectInvite(handle, 500, "failed to open device");
			return false;
		}
	}
	else if (state == MediaSession::kReady)
	{
		av::MediaChannelPtr mediaChannel = mediaSession->getMediaChannel();
		userDialog->setupAudio(mediaChannel, getMediaAddr(), 0);
	}

	if (userDialog->isMediaReady())
	{
		std::string userAnswer = makeUserAnswer(userDialog);

		HeaderFieldValue hfv(userAnswer.c_str(), userAnswer.size());
		Mime type("application", "sdp");
		SdpContents sdpAnswer(hfv, type);

		handle->provideAnswer(sdpAnswer);

		if (!handle->isAccepted())
		{
			ServerInviteSession* inviteSession = (ServerInviteSession*)handle.get();
			inviteSession->accept();
		}
	}

	return true;
}

void SipServer::handleMediaFormatReady(MediaSessionPtr& mediaSession, av::MediaFormat& fmt)
{
	handleMediaReady(mediaSession);
}

void SipServer::handleMediaReady(MediaSessionPtr& mediaSession)
{
	av::MediaChannelPtr channel = mediaSession->getMediaChannel();
	channel->startStream();

	mediaSession->setState(MediaSession::kReady);

	MediaSession::HandleArray handleArray = mediaSession->getUsers();
	for (size_t i = 0; i < handleArray.size(); i ++)
	{
		ServerInviteSessionHandle inviteHandle = handleArray[i];
		handleMediaReady(mediaSession, inviteHandle);
	}
}

void SipServer::handleMediaReady(MediaSessionPtr& mediaSession, ServerInviteSessionHandle handle)
{
	AppDialogHandle userDialogHandle = handle->getAppDialog();
	UserAppDialog* userDialog = dynamic_cast<UserAppDialog*>(userDialogHandle.get());
	if (!userDialog)
	{
		return;
	}

	av::MediaChannelPtr channel = mediaSession->getMediaChannel();

	userDialog->setupAudio(channel, getMediaAddr(), 0);

	if (userDialog->isMediaReady())
	{
		std::string userAnswer = makeUserAnswer(userDialog);

		HeaderFieldValue hfv(userAnswer.c_str(), userAnswer.size());
		Mime type("application", "sdp");
		SdpContents sdpAnswer(hfv, type);

		handle->provideAnswer(sdpAnswer);

		if (!handle->isAccepted())
		{
			handle->accept();
		}
	}
}

Uri SipServer::getContact(ClientRegistrationHandle& handle)
{
	Uri uri;
	const NameAddrs& addrs = handle->allContacts();
	if (!addrs.empty())
	{
		uri = addrs.front().uri();
	}
	return uri;
}

Uri SipServer::getContact(ServerRegistrationHandle& handle)
{
	Uri uri;
	const ContactList& contactList = handle->getRequestContacts();
	if (contactList.empty())
	{
		return uri;
	}

	ContactInstanceRecord contact = contactList.front();
	return contact.mContact.uri();
}

void SipServer::setupMasterProfile()
{
	NameAddr userAor;
	userAor.uri().host() = config().getString("Sip.IP", getHostAddr()).c_str();
	userAor.uri().port() = getLocalPort();
	userAor.uri().user() = config().getString("Sip.User", "hkgate").c_str();
	Data password = config().getString("Sip.Password", "").c_str();

	m_profile->setDefaultFrom(userAor);

	m_profile->setDigestCredential(userAor.uri().host(), userAor.uri().user(),
		password);

	m_profile->validateContentEnabled() = false;
	m_profile->validateAcceptEnabled() = false;
	m_profile->validateContentLanguageEnabled() = false;

	int sec = m_config.getInt("Sip.RegTime", 60);
	m_profile->setDefaultRegistrationTime(sec);
	m_profile->setDefaultMaxRegistrationTime(sec * 2);

	m_profile->setDefaultSessionTime(180);

	//m_profile->addSupportedOptionTag(Token(Symbols::Timer));
	//m_profile->addSupportedOptionTag(Token(Symbols::Replaces));

	m_profile->addSupportedMethod(resip::REGISTER);
	m_profile->addSupportedMethod(resip::INFO);
	m_profile->addSupportedMethod(resip::MESSAGE);
	m_profile->addSupportedMethod(resip::REFER);
	m_profile->addSupportedMethod(resip::PUBLISH);
	m_profile->addSupportedMethod(resip::SUBSCRIBE);
	m_profile->addSupportedMethod(resip::NOTIFY);

	m_dum->setMasterProfile(m_profile);
}

void SipServer::setupDum()
{
	bool enableAuth = false;
	m_config.get("Sip.EnableAuth", enableAuth);

	std::string realm = m_config.get("Sip.Realm");
	if (realm.empty())
	{
		realm = m_config.get("Sip.IP");
	}

	m_authManager.reset(new RegUserAuthManager(*m_dum, m_userStore, realm.c_str()));
	if (enableAuth)
	{
		m_dum->setServerAuthManager(m_authManager);
	}

	m_regManager.reset(new InMemorySyncRegDb());
	m_dum->setRegistrationPersistenceManager(m_regManager.get());
	m_dum->setServerRegistrationHandler(this);

	std::auto_ptr<ClientAuthManager> clientAuth(new ClientAuthManager());
	m_dum->setClientAuthManager(clientAuth);
	m_dum->setClientRegistrationHandler(this);

	std::auto_ptr<KeepAliveManager> keepAlive(new KeepAliveManager());
	KeepAliveManager::mKeepAlivePongTimeoutMs = 2;
	m_dum->setKeepAliveManager(keepAlive);

	m_dum->setInviteSessionHandler(this);

	m_dum->setClientPagerMessageHandler(this);
	m_dum->setServerPagerMessageHandler(this);

	m_dum->addOutOfDialogHandler(OPTIONS, this);

	std::auto_ptr<AppDialogSetFactory> dsf(new UserAppDialogSetFactory());
	m_dum->setAppDialogSetFactory(dsf);

	//m_dum->addClientSubscriptionHandler(Symbols::Presence, this);
	m_dum->addServerSubscriptionHandler(Symbols::Presence, this);

	m_dum->addExternalMessageHandler(this);
}


void SipServer::teardown()
{

}

void SipServer::onDumCanBeDeleted()
{
	m_shuttingDown = true;
}

void SipServer::thread()
{
	while (!isShutdown())
	{
		m_dum->process(1000);
	}

	m_dum->shutdown(this);

	teardown();
}



// server registration
/// Called when registration is refreshed
void SipServer::onRefresh(ServerRegistrationHandle handle, const SipMessage& reg)
{
	Uri uri = getContact(handle);

	handle->accept();

	RegUser regUser;
	if (!m_userStore.find(uri.user().c_str(), regUser))
	{
		CLog::warning("SipServer::onRefresh. the user is not found:%s\n", uri.user().c_str());
		return;
	}

	
}

/// called when one or more specified contacts is removed
void SipServer::onRemove(ServerRegistrationHandle handle, const SipMessage& reg)
{
	Uri uri = getContact(handle);

	handle->accept();

	CLog::info("SipServer::onRemove. sip:%s@%s:%d\n",
		uri.user().c_str(),
		uri.host().c_str(),
		uri.port());

}

/// Called when all the contacts are removed using "Contact: *"
void SipServer::onRemoveAll(ServerRegistrationHandle handle, const SipMessage& reg)
{
	Uri uri = reg.header(h_To).uri();
	//Uri uri = getContact(handle);
	handle->accept();

	CLog::info("SipServer::onRemoveAll. sip:%s@%s:%d\n",
		uri.user().c_str(),
		uri.host().c_str(),
		uri.port());


}

/** Called when one or more contacts are added. This is after
authentication has all succeeded */
void SipServer::onAdd(ServerRegistrationHandle handle, const SipMessage& reg)
{
	///
	Uri uri = getContact(handle);
	handle->accept();

	CLog::info("Registration. sip:%s@%s:%d\n",
		uri.user().c_str(),
		uri.host().c_str(),
		uri.port());

	RegUser regUser;
	if (!m_userStore.find(uri.user().c_str(), regUser))
	{
		CLog::warning("SipServer::onAdd. no found the user:%s\n", uri.user().c_str());
		return;
	}


}

/// Called when a client queries for the list of current registrations
void SipServer::onQuery(ServerRegistrationHandle handle, const SipMessage& reg)
{
	/// pass
}



/// Called when registraion succeeds or each time it is sucessfully
/// refreshed (manual refreshes only).
void SipServer::onSuccess(ClientRegistrationHandle handle, const SipMessage& response)
{
	Uri uri = getContact(handle);
	CLog::info("client reg success. sip:%s@%s:%d\n",
		uri.user().c_str(),
		uri.host().c_str(),
		uri.port());

	m_regHandle = handle;



}


// Called when all of my bindings have been removed
void SipServer::onRemoved(ClientRegistrationHandle handle, const SipMessage& response)
{
	Uri uri = getContact(handle);
	CLog::info("client reg failed. sip:%s@%s:%d\n",
		uri.user().c_str(),
		uri.host().c_str(),
		uri.port());
}


/// call on Retry-After failure.
/// return values: -1 = fail, 0 = retry immediately, N = retry in N seconds
int SipServer::onRequestRetry(ClientRegistrationHandle handle, int retrySeconds, const SipMessage& response)
{
	if (m_shuttingDown)
	{
		return -1;
	}

	if (m_regRetryDelayTime == 0)
	{
		m_regRetryDelayTime = BaseRegistrationRetryTimeAllFlowsFailed; // We only have one flow in this test app
	}

	// Use back off procedures of RFC 5626 section 4.5
	m_regRetryDelayTime = resipMin(MaxRegistrationRetryTime, m_regRetryDelayTime * 2);

	// return an evenly distributed random number between 50% and 100% of m_regRetryDelayTime
	int retryTime = Helper::jitterValue(m_regRetryDelayTime, 50, 100);
	InfoLog(
		<< "onRequestRetry(ClientRegistrationHandle): msg=" << response.brief() << ", retryTime=" << retryTime);

	return retryTime;
}


/// Called if registration fails, usage will be destroyed (unless a
/// Registration retry interval is enabled in the Profile)
void SipServer::onFailure(ClientRegistrationHandle handle, const SipMessage& response)
{
	Uri uri = getContact(handle);
	CLog::info("client reg failed. sip:%s@%s:%d\n",
		uri.user().c_str(),
		uri.host().c_str(),
		uri.port());
}


/// Called when a TCP or TLS flow to the server has terminated.  This can be caused by socket
/// errors, or missing CRLF keep alives pong responses from the server.
//  Called only if clientOutbound is enabled on the UserProfile and the first hop server
/// supports RFC5626 (outbound).
/// Default implementation is to immediately re-Register in an attempt to form a new flow.
void SipServer::onFlowTerminated(ClientRegistrationHandle handle)
{
}



// invite handler
/// called when an initial INVITE or the intial response to an outoing invite
void SipServer::onNewSession(ClientInviteSessionHandle handle, InviteSession::OfferAnswerType oat, const SipMessage& msg)
{
	// pass
}

void SipServer::onNewSession(ServerInviteSessionHandle handle, InviteSession::OfferAnswerType oat, const SipMessage& msg)
{
	/// 收到用户呼叫
	const NameAddr& peerAddr = handle->peerAddr();
	std::string peerUri = comn::StringCast::toString(peerAddr.uri());

	Data devNum = handle->myAddr().uri().user();
	Data userNum = handle->peerAddr().uri().user();

	CLog::info("onNewSession. %s => %s\n", peerUri.c_str(), devNum.c_str());

	handle->provisional(100);

	// 根据呼叫号码查找设备ID
	resip::Data deviceID;
	getDeviceID(devNum, deviceID);
	if (deviceID.empty())
	{
		deviceID = devNum;
	}

	av::MediaSystem::Device device;
	if (!m_mediaSystem->getDevice(deviceID.c_str(), device))
	{
		CLog::warning("can not find the device. num:%s\n", deviceID.c_str());
		handle->reject(404);
		return;
	}

	if (device.isEmpty())
	{
		handle->reject(404);
		return;
	}

	device.num = devNum.c_str();
	device.status = true;

	if (device.status <= 0)
	{
		rejectInvite(handle, 404, "device is offline.");
		return;
	}

	/// get user dialog
	AppDialogHandle dialogHandle = handle->getAppDialog();
	UserAppDialog* userDialog = dynamic_cast<UserAppDialog*>(dialogHandle.get());
	userDialog->m_device = device;

	std::shared_ptr<av::CRtpMediaChannel> audioChannel(new av::CRtpMediaChannel());
	userDialog->m_audioChannel = audioChannel;


	/// create media session
	MediaSessionPtr mediaSession = m_mediaSessionMap.findSession(device.id);
	if (mediaSession)
	{
		mediaSession->addUser(handle);

		bool canTalk = mediaSession->setTalker(handle);
		userDialog->canTalk(canTalk);
		audioChannel->enableRecv(canTalk);
	}
	else
	{
		mediaSession.reset(new MediaSession());
		mediaSession->addUser(handle);
		mediaSession->setMediaDev(device);

		mediaSession->setTalker(handle);
		userDialog->canTalk(true);
		audioChannel->enableRecv(true);

		av::MediaChannelPtr channel = m_mediaSystem->create(device.id);
		if (!channel)
		{
			handle->reject(404);
			return;
		}

		mediaSession->setMediaChannel(channel);

		m_mediaSessionMap.put(device.id.c_str(), mediaSession);
	}
}


/// Received a failure response from UAS
void SipServer::onFailure(ClientInviteSessionHandle handle, const SipMessage& msg)
{
	// pass
}


/// called when an in-dialog provisional response is received that contains a body
void SipServer::onEarlyMedia(ClientInviteSessionHandle handle, const SipMessage&, const SdpContents& contents)
{
}

void SipServer::onEarlyMedia(ClientInviteSessionHandle handle, const SipMessage&, const Contents& contents)
{
}


/// called when dialog enters the Early state - typically after getting 18x
void SipServer::onProvisional(ClientInviteSessionHandle handle, const SipMessage& msg)
{
}


/// called when a dialog initiated as a UAC enters the connected state
void SipServer::onConnected(ClientInviteSessionHandle handle, const SipMessage& msg)
{
	// pass
}


/// called when a dialog initiated as a UAS enters the connected state
void SipServer::onConnected(InviteSessionHandle handle, const SipMessage& msg)
{
	/// 用户呼叫建立成功

	const NameAddr& peerAddr = handle->peerAddr();
	std::string peerUri = comn::StringCast::toString(peerAddr.uri());

	Data devNum = handle->myAddr().uri().user();
	CLog::info("onConnected. user(%s) to %s\n", peerUri.c_str(), devNum.c_str());

	AppDialogHandle dialogHandle = handle->getAppDialog();
	UserAppDialog* userDialog = dynamic_cast<UserAppDialog*>(dialogHandle.get());

	if (userDialog)
	{
		/// 启动发流
		userDialog->startCast();
	}
}


void SipServer::onTerminated(InviteSessionHandle handle, InviteSessionHandler::TerminatedReason reason, const SipMessage* related)
{
	const NameAddr& peerAddr = handle->peerAddr();
	std::string peerUri = comn::StringCast::toString(peerAddr.uri());

	Data devNum = handle->myAddr().uri().user();

	CLog::info("onTerminated. user(%s) to %s\n", peerUri.c_str(), devNum.c_str());

	AppDialogHandle dialogHandle = handle->getAppDialog();
	UserAppDialog* userDialog = dynamic_cast<UserAppDialog*>(dialogHandle.get());

	if (userDialog)
	{
		ServerInviteSessionHandle inviteHandle(*m_dum, handle.getId());
		MediaSessionPtr mediaSession = m_mediaSessionMap.findSession(userDialog->m_device.id);
		if (mediaSession)
		{
			mediaSession->removeUser(inviteHandle);

			tryCloseSession(mediaSession);
		}
	}
}


/// called when a fork that was created through a 1xx never receives a 2xx
/// because another fork answered and this fork was canceled by a proxy.
void SipServer::onForkDestroyed(ClientInviteSessionHandle handle)
{
	/// pass
}


/// called when a 3xx with valid targets is encountered in an early dialog
/// This is different then getting a 3xx in onTerminated, as another
/// request will be attempted, so the DialogSet will not be destroyed.
/// Basically an onTermintated that conveys more information.
/// checking for 3xx respones in onTerminated will not work as there may
/// be no valid targets.
void SipServer::onRedirected(ClientInviteSessionHandle, const SipMessage& msg)
{

}


/// called when an answer is received - has nothing to do with user
/// answering the call
void SipServer::onAnswer(InviteSessionHandle handle, const SipMessage& msg, const SdpContents& contents)
{
	const NameAddr& peerAddr = handle->peerAddr();
	std::string peerUri = comn::StringCast::toString(peerAddr.uri());

	Uri targetUri = handle->peerAddr().uri();

	AppDialogHandle dialogHandle = handle->getAppDialog();
	UserAppDialog* userDialog = dynamic_cast<UserAppDialog*>(dialogHandle.get());
	
	if (userDialog)
	{
		CLog::info("onAnswer. user to dev(%s@%s:%d)\n",
		            targetUri.user().c_str(), targetUri.host().c_str(), targetUri.port());

		//ServerInviteSessionHandle inviteHandle(*m_dum, handle.getId());
		if (handleUserSdp(userDialog, handle, contents))
		{
			handleUserAnswer(userDialog, handle, contents);
		}
	}

}

/// called when an offer is received - must send an answer soon after this
void SipServer::onOffer(InviteSessionHandle handle, const SipMessage& msg, const SdpContents& contents)
{
	if (handle->isConnected())
	{
		/// 处理重呼reinvite
		ServerInviteSessionHandle inviteHandle(*m_dum, handle.getId());
		const Contents& answer = handle->getLocalOfferAnswer();
		inviteHandle->provideAnswer(answer);

		if (!inviteHandle->isAccepted())
		{
			inviteHandle->accept();
		}
		return;
	}

	const NameAddr& peerAddr = handle->peerAddr();
	std::string peerUri = comn::StringCast::toString(peerAddr.uri());

	Data devNum = handle->myAddr().uri().user();

	CLog::info("onOffer. %s => %s\n", peerUri.c_str(), devNum.c_str());

	AppDialogHandle dialogHandle = handle->getAppDialog();
    UserAppDialog* userDialog = dynamic_cast<UserAppDialog*>(dialogHandle.get());

    if (!handleUserSdp(userDialog, handle, contents))
    {
    	return;
    }

    handleUserOffer(userDialog, handle, contents);

}

/// called when an Invite w/out offer is sent, or any other context which
/// requires an offer from the user
void SipServer::onOfferRequired(InviteSessionHandle handle, const SipMessage& msg)
{
	const NameAddr& peerAddr = handle->peerAddr();
	std::string peerUri = comn::StringCast::toString(peerAddr.uri());

	Data devNum = handle->myAddr().uri().user();

	CLog::info("onOfferRequired. %s => %s\n", peerUri.c_str(), devNum.c_str());

	AppDialogHandle dialogHandle = handle->getAppDialog();
	

}


/// called if an offer in a UPDATE or re-INVITE was rejected - not real
/// useful. A SipMessage is provided if one is available
void SipServer::onOfferRejected(InviteSessionHandle handle, const SipMessage* msg)
{

}


/// called when INFO message is received
/// the application must call acceptNIT() or rejectNIT()
/// once it is ready for another message.
void SipServer::onInfo(InviteSessionHandle handle, const SipMessage& msg)
{
	std::string mime = ResipUtil::getMime(msg);
	handle->acceptNIT(200);
}


/// called when response to INFO message is received
void SipServer::onInfoSuccess(InviteSessionHandle, const SipMessage& msg)
{
	/// pass
}

void SipServer::onInfoFailure(InviteSessionHandle, const SipMessage& msg)
{
	/// pass
}


/// called when MESSAGE message is received
void SipServer::onMessage(InviteSessionHandle handle, const SipMessage& msg)
{
	handle->acceptNIT(200);
}


/// called when response to MESSAGE message is received
void SipServer::onMessageSuccess(InviteSessionHandle, const SipMessage& msg)
{
	// pass
}

void SipServer::onMessageFailure(InviteSessionHandle, const SipMessage& msg)
{
	// pass
}


/// called when an REFER message is received.  The refer is accepted or
/// rejected using the server subscription. If the offer is accepted,
/// DialogUsageManager::makeInviteSessionFromRefer can be used to create an
/// InviteSession that will send notify messages using the ServerSubscription
void SipServer::onRefer(InviteSessionHandle, ServerSubscriptionHandle, const SipMessage& msg)
{
	// pass
}


void SipServer::onReferNoSub(InviteSessionHandle, const SipMessage& msg)
{
	// pass
}


/// called when an REFER message receives a failure response
void SipServer::onReferRejected(InviteSessionHandle, const SipMessage& msg)
{
	// pass
}


/// called when an REFER message receives an accepted response
void SipServer::onReferAccepted(InviteSessionHandle, ClientSubscriptionHandle, const SipMessage& msg)
{
	// pass
}



// Called when a MESSAGE has been successfully sent
void SipServer::onSuccess(ClientPagerMessageHandle handle, const SipMessage& status)
{
	/// pass
}

// Application could re-page the failed contents or just ingore it.
void SipServer::onFailure(ClientPagerMessageHandle handle, const SipMessage& status, std::auto_ptr<Contents> contents)
{
	/// pass
}

void SipServer::onMessageArrived(ServerPagerMessageHandle handle, const SipMessage& message)
{
	const Mime& mimeType = message.header(h_ContentType);
	
}


//Client must call acceptUpdate or rejectUpdate for any onUpdateFoo
void SipServer::onUpdatePending(ClientSubscriptionHandle handle, const SipMessage& notify, bool outOfOrder)
{

}

void SipServer::onUpdateActive(ClientSubscriptionHandle handle, const SipMessage& notify, bool outOfOrder)
{

}

//unknown Subscription-State value
void SipServer::onUpdateExtension(ClientSubscriptionHandle handle, const SipMessage& notify, bool outOfOrder)
{

}

int SipServer::onRequestRetry(ClientSubscriptionHandle handle, int retrySeconds, const SipMessage& notify)
{
	return retrySeconds;
}

//subscription can be ended through a notify or a failure response.
void SipServer::onTerminated(ClientSubscriptionHandle handle, const SipMessage* msg)
{

}

//not sure if this has any value.
void SipServer::onNewSubscription(ClientSubscriptionHandle handle, const SipMessage& notify)
{

}


/// server sub
void SipServer::onNewSubscription(ServerSubscriptionHandle handle, const SipMessage& sub)
{
	handle->send(handle->accept());

	//handle->setSubscriptionState(Active);
	//handle->setSubscriptionState(Pending);

	handle->send(handle->neutralNotify());
}

void SipServer::onTerminated(ServerSubscriptionHandle handle)
{
	handle->end();
}

// Client Handlers
void SipServer::onSuccess(ClientOutOfDialogReqHandle handle, const SipMessage& successResponse)
{

}

void SipServer::onFailure(ClientOutOfDialogReqHandle handle, const SipMessage& errorResponse)
{

}

// Server Handlers
void SipServer::onReceivedRequest(ServerOutOfDialogReqHandle handle, const SipMessage& request)
{
	handle->send(handle->accept());
}

void SipServer::onMessage(ExternalMessageBase* externalMessage, bool& handled)
{
	MediaFormatReadyMessage* readyMsg = dynamic_cast<MediaFormatReadyMessage*>(externalMessage);
	if (readyMsg)
	{
		MediaSessionPtr mediaSession = m_mediaSessionMap.findSession(readyMsg->m_uri);
		if (mediaSession)
		{
			handleMediaFormatReady(mediaSession, readyMsg->m_fmt);

		}
	}
}

bool SipServer::findVideoMedium(const SdpContents& contents, RtpMedium& rtpMedium)
{
	const SdpContents::Session& session = contents.session();
	const SdpContents::Session::Medium* medium = ResipSdp::findMedium(session, "video");
	if (!medium)
	{
		return false;
	}

	const SdpContents::Session::Codec* codec = ResipSdp::findCodec(*medium, "H264");
	if (!codec)
	{
		codec = ResipSdp::findCodec(*medium, "PS");
	}

	return ResipSdp::parse(*medium, codec, rtpMedium);
}


static bool extractInt(const std::string& src, const char* strBegin,
	const char* strEnd, int& value)
{
	std::string substr = comn::StringUtil::extract(src, 0, strBegin, strEnd, false);
	comn::StringCast::toValue(substr, value);
	return !substr.empty();
}

bool SipServer::findH264Medium(const SdpContents& contents, RtpMedium& rtpMedium)
{
	std::string strSdp = ResipSdp::toString(contents);
	CLog::debug("%s\n", strSdp.c_str());

	const SdpContents::Session& session = contents.session();
	const SdpContents::Session::Medium* medium = ResipSdp::findMedium(session, "video");
	if (!medium)
	{
		return false;
	}

	const SdpContents::Session::Codec* codec = ResipSdp::findCodec(*medium, "H264", "packetization-mode=1");
	if (!codec)
	{
		return false;
	}

	if (medium->exists("imageattr"))
	{
		std::string imageattr = medium->getValues("imageattr").front().c_str();
		extractInt(imageattr, "x=", ",", rtpMedium.width);
		extractInt(imageattr, "y=", ",", rtpMedium.height);
	}

	return ResipSdp::parse(*medium, codec, rtpMedium);
}




void SipServer::rejectInvite(InviteSessionHandle& handle, int code)
{
	if (handle->isConnected())
	{
		handle->end();
	}
	else
	{
		handle->reject(code);
	}
}

void SipServer::rejectInvite(ClientInviteSessionHandle& handle, int code)
{
	if (handle->isConnected())
	{
		handle->end();
	}
	else
	{
		handle->reject(code);
	}
}

void SipServer::rejectInvite(ServerInviteSessionHandle& handle, int code)
{
	handle->reject(code);
}

void SipServer::rejectInvite(InviteSessionHandle& handle, int code, const char* reason)
{
	WarningCategory warning;
	warning.code() = code;
	warning.text() = reason;
	handle->reject(code, &warning);
}

void SipServer::rejectInvite(ServerInviteSessionHandle& handle, int code, const char* reason)
{
	WarningCategory warning;
	warning.code() = code;
	warning.text() = reason;
	if (handle->isConnected())
	{
		handle->end();
	}
	else
	{
		handle->reject(code, &warning);
	}
}

void SipServer::acceptInvite(InviteSessionHandle& handle)
{
	ServerInviteSession* serverSession = dynamic_cast<ServerInviteSession*>(handle.get());
	if (!serverSession)
	{
		return;
	}

	if (!serverSession->isAccepted())
	{
		serverSession->accept();
	}
}

void SipServer::acceptInvite(ServerInviteSessionHandle& handle)
{
	if (!handle->isAccepted())
	{
		handle->accept();
	}
}


void SipServer::startApplicationTimer(unsigned int timerId, unsigned int durationMs, unsigned int seqNumber, const Data& name)
{
	UserAgentTimeout t(*this, timerId, durationMs, seqNumber);
	t.setName(name);
	post(t, durationMs);
}

void SipServer::onApplicationTimer(unsigned int timerId, unsigned int durationMs, unsigned int seqNumber, const Data& name)
{
	if (timerId == TIMER_SERVER_REGISTRATION)
	{
		checkServerRegistrationExpire();

		startApplicationTimer(TIMER_SERVER_REGISTRATION, DURATION_SERVER_REGISTRATION, ++seqNumber, name);
	}
	else if (timerId == TIMER_DEVICE_SESSION)
	{
		//checkDeviceSessionExpire(name);
	}
}

void SipServer::post(ApplicationMessage& message, unsigned int ms)
{
	if (ms > 0)
	{
		m_stack.postMS(message, ms, m_dum.get());
	}
	else
	{
		m_dum->post(&message);
	}
}

void SipServer::checkServerRegistrationExpire()
{


}


int SipServer::handleJsonApi(const mg_str& method, const mg_str& uri,
		const mg_str& query, const mg_str& body,
		std::string& json)
{
//	if (0 == mg_vcmp(&uri, "/record/start"))
//	{
//		return handleStartRecord(query, json);
//	}
//	else if (0 == mg_vcmp(&uri, "/record/stop"))
//	{
//		return handleStopRecord(query, json);
//	}
	return 0;
}

void SipServer::handleUpload(const char* name, const std::string& filepath)
{
	//
}

int SipServer::handleFileApi(const mg_str& method, const mg_str& uri,
		const mg_str& query, const mg_str& body,
		std::string& resp, std::string& mime)
{
	return 404;
}

void SipServer::handleWebSocketFrame(unsigned char *data, size_t size, unsigned char flags)
{

//	if (m_httpServer)
//	{
//		m_httpServer->broadcast(data, size);
//	}

}

void SipServer::onDeviceStatus(const av::MediaSystem::Device& device)
{
	/// 设备上下线

	CLog::debug("device %s status: %d\n", device.id.c_str(), device.status);
}


bool SipServer::getDeviceID(const Data& num, Data& deviceID)
{
	bool found = false;
	std::string section = "Device";
	std::vector< std::string> keys = config().getKeys(section);
	for (size_t i = 0; i < keys.size(); ++i)
	{
		std::string key = keys[i];
		std::string path = section + AppConfig::SEPERATOR;
		path += key;

		std::string value;
		config().get(path, value);

		if (value == num.c_str())
		{
			deviceID = key.c_str();
			found = true;
			break;
		}
	}
	return found;
}